package com.zzy.service.impl;

import com.zzy.dao.BaseDao;
import com.zzy.model.*;
import com.zzy.service.*;
import com.zzy.util.activiti.UtilFlow;
import org.activiti.engine.*;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.*;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLinkType;
import org.activiti.engine.task.Task;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**自定义的flow的工具service
 *  @Author zzy
 *  @Time 2018年11月21日
 */

@Transactional
@Service()
public class FlowServiceImpl implements FlowService {
    @Autowired
    private BaseDao<FlowStatus> basedao;

    @Resource
    private ProcessEngine engine;
    @Autowired
    private UserService userService;
    @Autowired
    private UtilService utilService;
    @Autowired
    private RepositoryService repositoryService;


    private static RepositoryServiceImpl repositoryServiceImpl ;

    static {
        if(repositoryServiceImpl==null){
            repositoryServiceImpl = new RepositoryServiceImpl();
        }
    }


    @Autowired
    private ManagementService managementService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private FlowStepService flowStepService;
    @Autowired
    private FlowAuditService flowAuditService;


    public String startFlow(Map<String, Object> map, String processKey) {

        //RuntimeService runtimeService = engine.getRuntimeService();

        Map<String,Object> pd = UtilFlow.getProcessDefinitionInfo(processKey,repositoryServiceImpl);
        if(pd.isEmpty()){return null;}
        String pdId = MapUtils.getString(pd, "pdId");
        //获取全部环节。为流程环节动态添加处理
        List<Map<String, Object>> activities = UtilFlow.getCandidateUserExpressions(pdId,repositoryServiceImpl);
        for (Map<String, Object> activity : activities){
            List<String> candidates = (List<String>) activity.get("candidates");
            if (candidates.isEmpty()){continue;}
            for(String cand :candidates){// 3.获取对应角色的人员
                map.put(cand, userService.getUserIdsByRole(cand));
            }
        }
        String processInstanceId = UtilFlow.createProcessInstance(map,pdId,runtimeService);//启动流程
        return processInstanceId;
    }

    public void unStartFlow() {

    }

    public void getNextNode() {

    }

    /**
     * 保存流程结束状态
     * @param flowStatus
     * @Author:ADMIN
     */
    public void saveActStatus(FlowStatus flowStatus){
        basedao.save(flowStatus);
    }

    public void createDeployment(){
        DeploymentBuilder build=repositoryService.createDeployment();
        //	build.addZipInputStream(paramZipInputStream)  加载zip流方式
        build.addClasspathResource("MyProcess.bpmn");
        build.deploy();

    }




    public String  version(){
        return ProcessEngine.VERSION;
    }


    public List<Map<String, Object>> findTask(String userId,String bussinssType) {
        List<Map<String,Object>> result = new ArrayList<Map<String,Object>>();
        List<Task> tasks = UtilFlow.queryTask(userId,bussinssType,taskService);
        for(Task task :tasks){
            Map<String,Object> map = new HashMap<String,Object>();
            String taskName = task.getName();
            String taskId = task.getId();
            String processInstanceId = task.getProcessInstanceId();
            map.put("taskName", taskName);
            map.put("taskId", taskId);
            map.put("processInstanceId", processInstanceId);
            result.add(map);
        }
        return result;
    }


    public TaskInfo getCurrentTask(String procInsId){
        List<Task> curTasks = taskService.createTaskQuery().processInstanceId(procInsId).active().list();

        if(curTasks==null ||curTasks.size()==0){
            return null;
        }

        Task task=curTasks.get(0);

        System.out.println("类型："+task.getCategory());

        TaskInfo taskInfo=new TaskInfo(task.getProcessDefinitionId(),task.getId(),task.getName(),task.getTaskDefinitionKey());

        return taskInfo;

    }


    public Task getNextTask(String procInsId,String userId){
        Task task = taskService.createTaskQuery()
                .taskCandidateOrAssigned(userId)
                .processInstanceId(procInsId)
                .orderByTaskCreateTime().asc().singleResult();
        return task;

    }


    public void saveSuspendProcessInstance(String procInsId){
        runtimeService.suspendProcessInstanceById(procInsId);
    }



    public void saveActivateProcessInstance(String procInsId){
        runtimeService.activateProcessInstanceById(procInsId);
    }

    public void saveComplete(CompleteParams actParams){

        Assert.isTrue(StringUtils.hasText(actParams.getTaskIds()), "审核任务ID不能为空");
        if(!actParams.getType().equals(ActEnumType.COMMIT)){

            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

            User user2 = (User)request.getSession().getAttribute("user");

            Task task=this.getNextTask(actParams.getProcInsId(),user2.getId());

            Assert.isTrue(task!=null, "您当前无待审核任务!");

            Assert.isTrue(task.getId().equals(actParams.getTaskIds()), "您当前处理的任务不匹配!");
        }

        //封装actitivi 参数
        Map<String, Object> variables=new HashMap();

        this.setMapParams(variables, actParams);

        TaskInfo taskInfo=this.getCurrentTask(actParams.getProcInsId());

        if(taskInfo!=null){
            actParams.setStepCode(taskInfo.getDefinitionKey());
            actParams.setStepName(taskInfo.getTaskName());
        }

        //保存流程节点经过的步骤
        String actTaskId= flowStepService.save(actParams);
        actParams.setActTaskId(actTaskId);
        //保存审核结果
        flowAuditService.save(actParams);
        taskService.complete(actParams.getTaskIds(), variables);
    }


    private void setMapParams(Map<String,Object> variables,CompleteParams actParams){

        if(StringUtils.hasText(actParams.getUser())){//审核人
            variables.put("user", actParams.getUser());
        }
        if(StringUtils.hasText(actParams.getLinkurl())){//连接地址
            variables.put("linkurl", actParams.getLinkurl());
        }
        if(StringUtils.hasText(actParams.getOpinion())){//审核意见
            variables.put("opinion", actParams.getOpinion());
        }

        if(StringUtils.hasText(actParams.getApprove())){//审核结果
            variables.put("state",actParams.getApprove());
        }else{
            variables.put("state","y");
        }

        String auditor = actParams.getAuditor();
        if(StringUtils.hasText(auditor)){// 下一节点审核人
            variables.put("auditor", auditor);
        }

        if(actParams.getOther()!=null){//其他
            variables.put("other", actParams.getOther());
        }
    }



    public boolean isBreach(String procInsId){

        ExecutionEntity execution = (ExecutionEntity) runtimeService.createProcessInstanceQuery()
                .processInstanceId(procInsId).singleResult();
        if(execution == null){return false;}//流程已经结束
        ProcessDefinitionEntity def = (ProcessDefinitionEntity) repositoryServiceImpl.getDeployedProcessDefinition(execution.getProcessDefinitionId());
        // 根据流程实例id获取流程实例
        ProcessInstance pi=runtimeService.createProcessInstanceQuery().processInstanceId(procInsId) .singleResult();
        ActivityImpl activityImpl=def.findActivity(pi.getActivityId()); // 根据活动id获取活动实例
        if(activityImpl == null){return false;}
        List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();//获取从某个节点出来的所有线路
        for(PvmTransition tr:outTransitions){
            PvmActivity ac = tr.getDestination(); //获取线路的终点节点
            if("exclusiveGateway".equals(ac.getProperty("type"))){ //是网关
                List<PvmTransition> outTransitionsTemp = ac.getOutgoingTransitions();
                if(outTransitionsTemp.size() > 1){//网关后有多条连线
                    return true;
                } else {
                    return false;
                }
            } else if("userTask".equals(ac.getProperty("type"))){ //是任务节点
                return false;
            }
        }
        return false;
    }


    public void delectProcessInstance(String processInstanceId){
        if(!StringUtils.hasText(processInstanceId)){return ;}
        List<Task> curTasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId).active().list();
        if (curTasks != null && curTasks.size() !=0){
            //该流程实例未结束的
            runtimeService.deleteProcessInstance(processInstanceId,"");
        }
        delectTask(processInstanceId);
    }

    public void sendMessage(String taskId,String approve,String initiator,String moduleName,String stiName,String stiId,String nodeName) {
        managementService.executeCommand(new SendMessageCom(taskId,approve,initiator,moduleName,stiName,stiId,nodeName));
    }

    public void jumpTaskCmd(String executionId, String desActivityId,
                            String currentActivityId,String processDefinitionId){
        managementService.executeCommand(new JumpTaskCmd(executionId, desActivityId, currentActivityId, processDefinitionId));
    }

    public void saveHandler(String processInstanceId,String ids){
        managementService.executeCommand(new SaveHandlerCom(processInstanceId, ids));
        Assert.isTrue(false);
    }



    public String getStatus(String processInstanceId){
        String sql = "select * from act_status where procinsid = :procinsid";
        List<FlowStatus> list =  basedao.find(" from FlowStatus where procinsid=? ",new Object[]{processInstanceId});
        Assert.isTrue(list.size()>0,"数据错误");
        FlowStatus actStatus = list.get(0);
        return actStatus.getStatus();
    }

    public class SendMessageCom implements Command<Void> {
        protected String taskId;
        protected String approve;
        protected String initiator;
        protected String moduleName;
        protected String stiName;
        protected String stiId;
        protected String nodeName;

        public Void execute(CommandContext commandContext) {
            List<IdentityLinkEntity>  taskIdentityLinkEntities = Context.getCommandContext().getIdentityLinkEntityManager()
                    .findIdentityLinksByTaskId(taskId);
            for (IdentityLinkEntity identityLinkEntity : taskIdentityLinkEntities) {
                if (IdentityLinkType.CANDIDATE.equals(identityLinkEntity.getType())) {
                    String userId = identityLinkEntity.getUserId();
                    /**给下一节点用户发送消息*/
                    if("n".equals(approve)){

                    } else if("y".equals(approve)){

                    }
                }
            }
            return null;
        }

        public SendMessageCom(String taskId,String approve,String initiator,String moduleName,String stiName,String stiId,String nodeName) {
            super();
            this.taskId = taskId;
            this.approve = approve;
            this.initiator = initiator;
            this.moduleName = moduleName;
            this.stiName = stiName;
            this.stiId = stiId;
            this.nodeName = nodeName;
        }

    }

    public class JumpTaskCmd implements Command<Void>{
        protected String executionId;
        protected String desActivityId;  //目标节点
        protected String currentActivityId;  //当前节点
        protected String processDefinitionId;

        public Void execute(CommandContext commandContext) {
            ProcessDefinitionEntity def = (ProcessDefinitionEntity) repositoryServiceImpl.getDeployedProcessDefinition(processDefinitionId);
            ActivityImpl desActivity = def.findActivity(desActivityId);// 目标节点
            ActivityImpl currentActivity = def.findActivity(currentActivityId);// 当前节点

            ExecutionEntityManager executionEntityManager = Context.getCommandContext().getExecutionEntityManager();
            // 获取当前流程的executionId，因为在并发的情况下executionId是唯一的。
            ExecutionEntity executionEntity = executionEntityManager.findExecutionById(executionId);
            executionEntity.setEventSource(currentActivity);
            executionEntity.setActivity(currentActivity);

            Iterator<TaskEntity> localIterator = Context.getCommandContext().getTaskEntityManager()
                    .findTasksByExecutionId(this.executionId).iterator();  // 根据executionId 获取Task

            while (localIterator.hasNext()) {
                TaskEntity taskEntity = (TaskEntity) localIterator.next();
                //taskEntity.fireEvent("complete"); // 触发任务监听
                Context.getCommandContext().getTaskEntityManager().deleteTask(taskEntity, "completed", false);
            }
            executionEntity.executeActivity(desActivity);
            return null;
        }

        /**
         * 构造参数 可以根据自己的业务需要添加更多的字段
         * @param executionId
         */
        public JumpTaskCmd(String executionId, String desActivityId,
                           String currentActivityId,String processDefinitionId) {
            this.executionId = executionId;
            this.desActivityId = desActivityId;
            this.currentActivityId = currentActivityId;
            this.processDefinitionId = processDefinitionId;
        }
    }

    public class SaveHandlerCom implements Command<Void>{
        private String processInstanceId;
        private String ids;

        public Void execute(CommandContext commandContext) {
            List<TaskEntity>  taskEntitys = commandContext.getTaskEntityManager().findTasksByProcessInstanceId(processInstanceId);
            List<String> list = Arrays.asList(ids.split(","));
            for (TaskEntity taskEntity : taskEntitys) {
                taskEntity.addCandidateUsers(list);
            }
            return null;
        }
        public SaveHandlerCom(String processInstanceId,String ids) {
            super();
            this.processInstanceId = processInstanceId;
            this.ids = ids;
        }
    }

  public void delectTask(String processInstanceId){
      processInstanceId = processInstanceId.replaceAll("\'","");
      String sql = " DELETE s,a FROM flow_node_step s "
              + " LEFT JOIN flow_node_audit a ON s.id = a.step_id "
              + " WHERE step.pro_id = '"+processInstanceId+"' ";
      basedao.executeSql(sql);//执行删除
  }
}
